<template>
  <div class="map-container">
    <div ref="mapContainerDom" class="map-container"></div>
  </div>
</template>

<script lang="ts" setup>
import { OlUtil } from '../../lib/index'
import { onMounted, nextTick, ref, onBeforeUnmount } from 'vue'
import { Map, Feature } from 'ol'
import { get, Projection } from 'ol/proj'
import VectorLayer from 'ol/layer/Vector'
import VectorSource from 'ol/source/Vector'
import Point from 'ol/geom/Point'
import { Circle, Fill, Stroke, Style } from 'ol/style'
import { Kriging } from '../../lib/utils/kriging'
import { isobands, featureCollection, intersect, polygon as turfPolygon } from '@turf/turf'
import { GeoJSON } from 'ol/format'
import { Isosurfaces } from '../../lib/utils/isosurfaces'
import dispersionData from '../data/dispersion.json'
const mapConfig = {
  defaultShowMap: 'img',
  imgMapType: 'WMTS',
  imgMapUrl: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer',
  vecMapType: 'XYZ',
  vecMapUrl: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
  projectionCode: 'EPSG:3857',
  center: [81.8018641, 41.7792352],
  zoom: 15,
  maxZoom: 20,
  minZoom: 4,
  imgBaseUrl: ''
}

const olutil = new OlUtil()
let map: Map
const mapLoaded = ref(false)
let observer: ResizeObserver | null = null // 地图dom大小监听
const mapContainerDom = ref() // 地图容器

let mapProjection: Projection | undefined
const projectionCode = mapConfig.projectionCode || 'EPSG:3857'
if (projectionCode === 'EPSG:4490') {
  mapProjection = olutil.defineProjection_4490()
} else {
  mapProjection = get(projectionCode) as Projection
}
let ram: any
if (mapProjection) {
  ram = olutil.getResolutionsAndMids(mapProjection) // 获取分辨率和层级矩阵
}
const showMapType = ref(mapConfig.defaultShowMap) // 当前显示底图类型

// 加载地图
const loadMap = (id: string, mapUrl: string, type: string) => {
  let layer
  if (type === 'XYZ') {
    layer = olutil.loadXYZLayer({
      id,
      url: mapUrl,
      projection: mapConfig.projectionCode
    })
  } else if (type === 'WMTS') {
    layer = olutil.loadWMTSLayer({
      id,
      url: mapUrl,
      matrixSet: 'default028mm',
      projection: mapProjection,
      resolutions: ram.resolutions,
      matrixIds: ram.matrixIds
    })
  }
  layer && layer.setVisible(mapConfig.defaultShowMap === id)
  return layer
}
// 初始化地图
const initMap = () => {
  const vecMapLayer = loadMap('vec', mapConfig.vecMapUrl, mapConfig.vecMapType)
  const imgMapLAyer = loadMap('img', mapConfig.imgMapUrl, mapConfig.imgMapType)

  map = olutil.initMap(mapContainerDom.value, {
    // projection: 'EPSG:3857',
    center: mapConfig.center || [87.62, 43.83],
    zoom: mapConfig.zoom || 8,
    minZoom: mapConfig.minZoom || 6,
    maxZoom: mapConfig.maxZoom || 18,
    layers: [imgMapLAyer, vecMapLayer!]
  })
}

// 创建点图层
const createTextMarkerLayer = (pointArr: Array<any>) => {
  if (!map) return
  olutil.createTextMarkerLayer('pointsText', pointArr, { showTextKey: 'z' })
}

// 计算等值面
const selectedFeatures: Array<any> = [] // 选中的面数据
const computeIsosurfaces = () => {
  if (!map) return
  let WFSVectorSource = new VectorSource()
  let WFSVectorLayer = new VectorLayer({
    source: WFSVectorSource
  })
  map.addLayer(WFSVectorLayer)
  const pointArr = [
    { x: 87.62, y: 43.83, z: 5 }, // 小雨
    { x: 87.63, y: 43.84, z: 15 }, // 中雨
    { x: 87.61, y: 43.82, z: 2 }, // 毛毛雨
    { x: 87.625, y: 43.835, z: 25 }, // 中到大雨
    { x: 87.615, y: 43.825, z: 40 }, // 大雨
    { x: 87.64, y: 43.85, z: 60 }, // 暴雨
    { x: 87.6, y: 43.8, z: 80 }, // 大暴雨
    { x: 87.635, y: 43.845, z: 100 }, // 特大暴雨
    { x: 87.605, y: 43.815, z: 120 }, // 极端降雨
    { x: 87.645, y: 43.855, z: 150 } // 超强降雨
  ]

  // 根据pointArr数据动态生成province区域
  const xValues = pointArr.map((p) => p.x)
  const yValues = pointArr.map((p) => p.y)
  const minX = Math.min(...xValues)
  const maxX = Math.max(...xValues)
  const minY = Math.min(...yValues)
  const maxY = Math.max(...yValues)

  // 根据pointArr数据动态生成平滑的不规则多边形区域
  const centerX = (minX + maxX) / 2
  const centerY = (minY + maxY) / 2
  const radiusX = (maxX - minX) * 0.35 // x轴半径
  const radiusY = (maxY - minY) * 0.25 // y轴半径

  // 生成平滑的曲线多边形
  const sides = 8 // 边数越多越平滑
  const province: Array<Array<number>> = []
  for (let i = 0; i < sides; i++) {
    const angle = (i * 2 * Math.PI) / sides
    // 使用正弦函数添加平滑波动
    const waveFactor = 0.15 * Math.sin(angle * 3) + 1
    const x = centerX + radiusX * Math.cos(angle) * waveFactor
    const y = centerY + radiusY * Math.sin(angle) * waveFactor
    province.push([x, y])
  }
  // 闭合多边形
  province.push([...province[0]])

  // 构造面数据
  for (let i = 0; i < pointArr.length; i++) {
    let feature = new Feature({
      geometry: new Point([pointArr[i].x, pointArr[i].y]),
      value: pointArr[i].z
    })
    WFSVectorSource.addFeature(feature)
  }
  let extent = WFSVectorLayer!.getSource()!.getExtent()
  WFSVectorSource.forEachFeatureIntersectingExtent(extent, (feature) => {
    selectedFeatures.push(feature)
  })

  // 计算等值面
  let values: Array<number> = [],
    lngs: Array<number> = [],
    lats: Array<number> = []
  selectedFeatures.forEach((feature) => {
    values.push(feature.values_.value)
    lngs.push(feature.values_.geometry.flatCoordinates[0])
    lats.push(feature.values_.geometry.flatCoordinates[1])
  })
  const params = {
    krigingModel: 'exponential', // 克里金模型类型 'gaussian' - 高斯模型 'exponential' - 指数模型 'spherical' - 球面模型
    krigingSigma2: 0.01, // 测量误差方差(通常设置在 0.1 到 10 之间，值越小表示对原始数据的拟合越精确（可能过拟合）值越大表示允许更多平滑（可能欠拟合）)
    krigingAlpha: 0.5, // 克里金模型参数 值越大表示空间相关性衰减越快（影响范围小） 值越小表示空间相关性衰减越慢（影响范围大）
    colors: [
      'rgba(230, 245, 224, 0.9)', // 微量降雨 (浅绿)
      'rgba(161, 217, 155, 0.9)', // 小雨 (绿)
      'rgba(102, 189, 99, 0.9)', // 中雨 (深绿)
      'rgba(65, 182, 196, 0.9)', // 中到大雨 (蓝绿)
      'rgba(66, 165, 245, 0.9)', // 大雨 (蓝)
      'rgba(100, 149, 237, 0.9)', // 暴雨 (深蓝)
      'rgba(147, 112, 219, 0.9)', // 大暴雨 (蓝紫)
      'rgba(186, 104, 200, 0.9)', // 特大暴雨 (紫)
      'rgba(171, 71, 188, 0.9)', // 极端降雨 (深紫)
      'rgba(142, 36, 170, 0.9)' // 超强降雨 (紫红)
    ]
  }
  const kriging = new Kriging()
  let variogram = kriging.train(values, lngs, lats, params.krigingModel, params.krigingSigma2, params.krigingAlpha)
  let polygons: any = []
  polygons.push([
    [extent[0], extent[1]],
    [extent[0], extent[3]],
    [extent[2], extent[3]],
    [extent[2], extent[1]]
  ])
  let grid = kriging.grid(polygons, variogram, (extent[2] - extent[0]) / 100)

  if (WFSVectorLayer !== null) {
    map.removeLayer(WFSVectorLayer)
  }

  // 检查grid是否为有效对象
  if (!grid || typeof grid !== 'object' || !grid.list || !Array.isArray(grid.list)) {
    console.error('Invalid grid data:', grid)
    return
  }

  // 获取最大和最小值
  const minValue = Math.min(...values)
  const maxValue = Math.max(...values)
  // 根据值获取颜色
  function getColorForValue(value: string, minValue: number, maxValue: number): string {
    const numValue = Math.round(parseFloat(value.split('-')[1]))
    // 确保index在合理范围内
    const index = Math.min(
      Math.max(0, Math.floor(((numValue - minValue) / (maxValue - minValue)) * params.colors.length)),
      params.colors.length - 1
    )
    return params.colors[index] || params.colors[0] // 默认返回第一个颜色
  }
  let vectorSource = new VectorSource()
  WFSVectorLayer = new VectorLayer({
    zIndex: 10,
    source: vectorSource,
    style: function (feature) {
      const value = feature.get('value')
      // 根据值设置不同颜色
      const color = getColorForValue(value, minValue, maxValue)
      return new Style({
        fill: new Fill({
          color: color
        }),
        // 使用与填充色相同的颜色避免相邻区域出现黑边
        stroke: new Stroke({
          color: color.replace(/[\d\.]+\)$/, '1)'), // 移除透明度
          width: 0.5 // 使用更细的线宽
        })
      })
    }
  })

  // 直接使用grid数据创建点网格
  const features = grid.list
    .map((row, rowIndex) => {
      return row.map((value, colIndex) => {
        const x = extent[0] + (colIndex * (extent[2] - extent[0])) / (row.length - 1)
        const y = extent[1] + (rowIndex * (extent[3] - extent[1])) / (grid.list.length - 1)
        return {
          type: 'Feature',
          geometry: {
            type: 'Point',
            coordinates: [x, y]
          },
          properties: {
            value: value
          }
        }
      })
    })
    .flat()

  const pointGridData: any = {
    type: 'FeatureCollection',
    features: features
  }

  // 确保断点与数据范围匹配
  let breaks: any = []
  for (let i = 0; i <= 10; i++) {
    breaks.push(minValue + ((maxValue - minValue) * i) / 10)
  }
  let _isobands = isobands(pointGridData, breaks, { zProperty: 'value' })

  const ifClip = true // 是否裁剪
  let polyFeatures
  if (!ifClip) {
    polyFeatures = new GeoJSON().readFeatures(_isobands, {
      featureProjection: 'EPSG:4326'
    })
  } else {
    const clippedFeatures = _isobands.features
      .map((feature) => {
        const provinceFeature: any = turfPolygon([province])
        const clipped = intersect(featureCollection([feature, provinceFeature]))
        if (clipped) {
          clipped.properties = feature.properties
        }
        return clipped
      })
      .filter(Boolean) // 过滤掉null结果
    const _clippedFeatures = {
      type: 'FeatureCollection',
      features: clippedFeatures
    }
    polyFeatures = new GeoJSON().readFeatures(_clippedFeatures, {
      featureProjection: 'EPSG:4326'
    })
  }

  vectorSource.addFeatures(polyFeatures)

  WFSVectorLayer.set('id', 'WFSVectorLayer')
  map.addLayer(WFSVectorLayer)
  olutil.goToLayer('WFSVectorLayer')

  createTextMarkerLayer(pointArr)
  // 确保文本标记图层在降雨图层之上
  const pointsTextLayer = olutil.getLayer('pointsText')
  if (pointsTextLayer) {
    pointsTextLayer.setZIndex(20) // 设置高于WFSVectorLayer的zIndex(10)
  }
}

/**
 * 气体泄漏模型分析结果展示代码块
 */

// 根据中心点计算便宜点位信息
const offsetLatLng = (origin: any, dx: any, dy: any) => {
  const lng = origin[0] + dx / (111000 * Math.cos((origin[1] * Math.PI) / 180))
  const lat = origin[1] + dy / 111000
  return [lng, lat]
}

// 获取对应颜色
const getColor = (cppm: number) => {
  if (cppm < 1) return null
  if (cppm < 5) return '#3399ff'
  if (cppm < 10) return '#00cc66'
  if (cppm < 50) return '#ffff00'
  if (cppm < 100) return '#ff8000'
  return '#ff0000'
}

// 气体浓度场点位样式方法
const concentrationPointsStyleFunc = (feature: any) => {
  const attributes = feature.get('attributes')
  const color = attributes.color
  return new Style({
    image: new Circle({
      radius: 4,
      fill: new Fill({
        color: color
      })
    })
  })
}
// 生成气体浓度场点位效果
const createConcentrationPoints = () => {
  const center = [81.6418, 41.7317]
  const data = dispersionData
  // 处理数据，转换坐标为经纬度
  const pointArr: any = []
  data.cppm_grid.forEach((item: any) => {
    const xy = offsetLatLng(center, item.x, item.y)
    if (item.cppm >= 1) {
      pointArr.push({
        x: xy[0],
        y: xy[1],
        color: getColor(item.cppm),
        cppm: item.cppm
      })
    }
    // const color = getColor(item.cppm)
    // const itemdata: any = {
    //   x: xy[0],
    //   y: xy[1],
    //   cppm: item.cppm,
    //   // color
    // }
    // if (item.color) {
    //   const style = new Style({
    //     image: new CircleStyle({
    //       radius: 4,
    //       fill: new Fill({
    //         color: item.color
    //       })
    //     })
    //   })
    //   itemdata.style = style
    // }
    // if (item.cppm && item.cppm > 1) {
    //   pointArr.push(item)
    // }
  })
  console.log(pointArr, '---pointArr')
  const layer = olutil.createPointsLayer('point', pointArr)
  layer?.setStyle(concentrationPointsStyleFunc)
  olutil.goToLayer('point')
}

// 生成气体浓度场分布区域面
const createConcentrationField = () => {
  const center = [81.6418, 41.7317]
  const data = dispersionData
  // 处理数据，转换坐标为经纬度
  const pointArr: any = []
  data.cppm_grid.forEach((item: any) => {
    const xy = offsetLatLng(center, item.x, item.y)
    if (item.cppm && item.cppm >= 1) {
      pointArr.push({
        x: xy[0],
        y: xy[1],
        cppm: item.cppm
      })
    }
  })
  const isosurfaces = new Isosurfaces(map, olutil)
  // // 添加数据采样逻辑（保留5%-10%的关键点）
  // const sampleSize = Math.min(2000, Math.floor(pointArr.length * 0.05))
  // const sampledPoints = pointArr.sort(() => Math.random() - 0.5).slice(0, sampleSize)
  isosurfaces.computeIsosurfaces(pointArr, { valueField: 'cppm', id: 'isy' })
  const isyLayer = olutil.getLayer('isy') as VectorLayer
  isyLayer &&
    isyLayer.setStyle((feature: any) => {
      const value = feature.get('value')
      const numValue = Math.round(parseFloat(value.split('-')[1]))
      const color = getColor(numValue)
      return new Style({
        fill: new Fill({
          color: color
        }),
        // 使用与填充色相同的颜色避免相邻区域出现黑边
        stroke: new Stroke({
          color: color || 'fff',
          width: 0.5 // 使用更细的线宽
        })
      })
    })
  olutil.goToLayer('isy')
}
onMounted(() => {
  initMap()
  nextTick(() => {
    map &&
      map.once('rendercomplete', () => {
        mapLoaded.value = true
        // 监听地图dom大小变化
        observer = new ResizeObserver(() => {
          map && map.updateSize()
        })
        observer.observe(mapContainerDom.value)
        // createConcentrationField()
        createConcentrationPoints()
        // const isosurfaces = new Isosurfaces(map, olutil)
        // const pointArr = [
        //   { x: 87.62, y: 43.83, z: 5 }, // 小雨
        //   { x: 87.63, y: 43.84, z: 15 }, // 中雨
        //   { x: 87.61, y: 43.82, z: 2 }, // 毛毛雨
        //   { x: 87.625, y: 43.835, z: 25 }, // 中到大雨
        //   { x: 87.615, y: 43.825, z: 40 }, // 大雨
        //   { x: 87.64, y: 43.85, z: 60 }, // 暴雨
        //   { x: 87.6, y: 43.8, z: 80 }, // 大暴雨
        //   { x: 87.635, y: 43.845, z: 100 }, // 特大暴雨
        //   { x: 87.605, y: 43.815, z: 120 }, // 极端降雨
        //   { x: 87.645, y: 43.855, z: 150 } // 超强降雨
        // ]
        // isosurfaces.computeIsosurfaces(pointArr, { valueField: 'z', id: 'isy' })
        // olutil.goToLayer('isy')
      })
  })
})
onBeforeUnmount(() => {
  try {
    observer && observer.unobserve(mapContainerDom.value) // 移除监听
  } catch (err) {
    console.log(err)
  }
})
</script>
<script lang="ts">
export default {
  name: 'IsosurfacesMap'
}
</script>
<style lang="scss" scoped>
.map-container {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: hidden;
  .base-map-ctl {
    position: absolute;
    right: 0.2rem;
    bottom: 0.1rem;
    display: flex;
    background: rgba(31, 30, 30, 0.5);
    box-shadow: 2px 2px rgba(0, 0, 0, 0.4);
    border-radius: 3px;
    padding: 0.1rem;
    .map-type-img {
      height: 60px;
      width: 86px;
      cursor: pointer;
      border: 2px solid transparent;
    }

    .map-type-img-selected {
      border: 2px solid #2d8cf0;
    }
    .map-type-img:last-child {
      margin-left: 0.05rem;
    }
  }
  .map-ctl {
    position: absolute;
    left: 0.2rem;
    top: 0.2rem;
    display: flex;
    flex-direction: column;
    background: rgba(0, 0, 0, 0.5);
    padding: 0.1rem 0.08rem;
    border-radius: 4px;
    .map-ctl-item {
      margin-bottom: 0.1rem;
    }
    .map-ctl-item:last-child {
      margin-bottom: 0;
    }
  }
  .get-position-title {
    position: absolute;
    border: 1px solid #2d8cf0;
    background: white;
    padding: 0 4px;
    border-radius: 5px;
    pointer-events: none;
  }
}
</style>
